﻿using System;
using System.Collections.Generic;
using System.Text;

namespace SscLib
{
    public class InspectSymbol : ScopeSymbol
    {
        public readonly Symbol InspectedSymbol;

        internal InspectSymbol(VariableSymbol v)
            : base(v.Name, v.Type)
        {
            this.InspectedSymbol = v;
        }

        internal InspectSymbol(FieldSymbol f)
            : base(f.Name, f.Type)
        {
            this.InspectedSymbol = f;
        }

        /// <summary>
        /// Adds a new symbol in by defering to the parent scope.
        /// Inspect Scopes can not define any members.
        /// </summary>
        /// <param name="name">Name of symbol to add.</param>
        /// <param name="sym">The symbol to add.</param>
        public override void Add(string name, Symbol sym)
        {
            this.Scope.Add(name, sym);
        }

        /// <summary>
        /// Resolves the symbol name, by first looking through the inspected symbols Type.
        /// Then defers to the parent scope if symbol was not to be found in the inspected symbols type.
        /// </summary>
        /// <param name="name">Name og symbol to resolve.</param>
        /// <returns>The resolved symbol or null if symbol is not defined.</returns>
        public override Symbol Resolve(string name)
        {
            Symbol sym = InspectedSymbol.Type.Resolve(name);
            if (sym == null && this.Scope != null) sym = this.Scope.Resolve(name);
            return sym;
        }

        /// <summary>
        /// Searches for the named symbol and returns the enclosing scope if the scope is an InspectScope.
        /// </summary>
        /// <param name="s">Symbol for which to return the enclosing Inspect scope.</param>
        /// <returns>The enclosing Inspect Scope or null.</returns>
        public override InspectSymbol GetInspectForSymbol(Symbol s)
        {
            Symbol temp = null;

            TypeSymbol type = this.InspectedSymbol.Type;
            while (type != null)
            {
                if (type.Members.ContainsKey(s.Name))
                {
                    temp = type.Members[s.Name];
                    break;
                }
                type = type.BaseType;
            }

            if (temp == null && this.Scope != null) return this.Scope.GetInspectForSymbol(s);
            if (temp == s) return this;
            else return null;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("Inspect({0}):\n", this.InspectedSymbol.ToString());
            sb.AppendLine(this.InspectedSymbol.Type.ToString());
            return sb.ToString();
        }

        public override Dictionary<string, Symbol> Members
        {
            //I think bugfix, that we should return members of parent, 
            //since we should not add new members to an inspected scope
            //get { return this.InspectedSymbol.Type.Members; }
            get { return null; }
           // get { return this.parent.Members; }
            //Nei, den bugfixen viste seg å ikke fungere. Men vi må løse Add... problemet på en måte, tror jeg.
        }

        //public override System.Reflection.Emit.ILGenerator GetILGenerator()
        //{
        //    return this.Scope.GetILGenerator();
        //}
    }
}
